package com.common.image_loader;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Vector;

import android.graphics.Bitmap;

import com.baidu.common.utils.AppLog;

/**T
 * A bitmap cache with LRU mechanism.
 */
public class BitmapCache<K> extends LinkedHashMap<K, Bitmap> {

    /**
     * 
     */
    private static final long serialVersionUID = 3548954352544380038L;

    // Assume a 32-bit image
    private static final long BYTES_PER_PIXEL = 4;

    private static final int INITIAL_CAPACITY = 32;

    private static final float LOAD_FACTOR = 0.5f;

    private long mMaxBytes;

    private boolean mRemove;

    public String TAG = "MAIN CACHE";
    
    private int MAX_SIZE = 70;
    
    public void setMaxImageSize(int size)
    {
    	this.MAX_SIZE = size;
    }
    
    /**
     * Constructor.
     *
     * @param maxBytes the maximum size of the cache in bytes.
     */
    public BitmapCache(long maxBytes) {
        super(INITIAL_CAPACITY, LOAD_FACTOR, true);
        mMaxBytes = maxBytes;
    }

    static long sizeOf(Bitmap b) {
    	if(b == null) return 0;
        return b.getWidth() * b.getHeight() * BYTES_PER_PIXEL;
    }

    private static long sizeOf(Iterable<Bitmap> bitmaps) {
        long total = 0;
        for (Bitmap bitmap : bitmaps) 
        {
        	if(bitmap ==null)
        		continue;
            total +=bitmap.getRowBytes();
        }
        return total;
    }

    @Override
    protected boolean removeEldestEntry(java.util.Map.Entry<K, Bitmap> eldest) {
        return mRemove;
    }

    public void setTAG(String tag)
    {
    	this.TAG = tag;
    }
    /**
     * Removes the eldest entry if the cache is too big.
     */
    public void trimEldest() {
        // Remove null otherwise put() may have no effect
        super.remove(null);

        // Induce LinkedHashMap to remove the eldest element
        mRemove = true;
        try {
            super.put(null, null);
        } finally {
            mRemove = false;
        }

        // Remove null so that it does not appear in the key/entry sets
        super.remove(null);
    }

    public static long MAX = 30 * 1024 * 1024;
    /**
     * Removes additional elements until the cache is an acceptable size.
     * <p>
     * This method must be called after each insertion operation.
     */
    private void trimToSize() {
        // This runtime performance of this method is not great,
        // but it's less error-prone than maintaining a counter.
    	if(this.size() > 20 /*|| mMaxBytes > MAX*/)
    	{
            while (this.size() > 15) 
            {
                trimEldest();
            }
            AppLog.error(TAG, "trimToSize : " + "size = "+this.size());
            System.gc();
    	}
    }

    private NullPointerException nullKeyException() {
        // Null keys are not permitted because null is used by trim()
        return new NullPointerException("Key is null");
    }

    @Override
    public Bitmap put(K key, Bitmap value) {
        if (key == null) {
            throw nullKeyException();
        }
        try 
        {
            return super.put(key, value);
        } 
        finally 
        {
        	mMaxBytes += sizeOf(value);
            trimToSize();
        }
    }

    @Override
    public void putAll(Map<? extends K, ? extends Bitmap> map) {
        if (map.containsKey(null)) {
            throw nullKeyException();
        }
        
        try {
            super.putAll(map);
        } finally {
            trimToSize();
        }
    }

    @Override
    public Bitmap get(Object key) {
    	
    	System.out.println("trimToSize : " + "size = "+this.size());
        if (key == null) {
            throw nullKeyException();
        }
        if(this.parent != null)
        this.parent.get(key);
        return super.get(key);
    }

    @Override
    public boolean containsKey(Object key) {
        if (key == null) {
            throw nullKeyException();
        }
        return super.containsKey(key);
    }

    @Override
    public Bitmap remove(Object key) {
        if (key == null) {
            throw nullKeyException();
        }
        return super.remove(key);
    }
    
    public void setParent(BitmapCache<String> parent)
    {
    	this.parent = parent;
    }
    
    public BitmapCache<String> getParentCache()
    {
    	return this.parent;
    }
    
    private BitmapCache<String> parent ;
    
    private Vector<BitmapCache<String>> refers ;
    
    public void setRefers(Vector<BitmapCache<String>> refers)
    {
    	this.refers = refers;
    }
    
    public Vector<BitmapCache<String>> getRefers()
    {
    	return this.refers;
    }
}
